package com.bfb;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.location.Address;
import android.location.Geocoder;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.bfb.R;
import com.bfb.helpers.ServerUtilities;

/**
 * This activity is used for displaying & setting dishes' locations through a
 * map view
 * 
 * @author Dina Helal
 * 
 */
public class MapViewActivity extends MapActivity {
	static String PATH1 = "/location";
	static String PATH2 = "/dish_img";
	LinearLayout linearLayout;
	MapView mapView;
	List<Overlay> mapOverlays;
	Drawable drawable;
	MapOverlay itemizedOverlay;
	String latitude, longitude;
	GeoPoint p = null;
	String restaurant_id = "";
	String restaurant_name = "";
	Bitmap dishImg;
	JSONObject query;
	JSONArray results;
	String area = "";
	static URL myURL;
	static URLConnection uc;
	static InputStream in;
	boolean img_retrived = false;
	boolean loca_retrived = false;
	String not_found = "";
	/***
	 * Called when the activity is first created Initializes variables &
	 * retrieves data from the bundle
	 * 
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		setContentView(R.layout.map_view);
		mapView = (MapView) findViewById(R.id.mapView);
		mapView.setBuiltInZoomControls(true);
		mapOverlays = mapView.getOverlays();
		drawable = this.getResources().getDrawable(R.drawable.google_pin);
		itemizedOverlay = new MapOverlay(drawable);
		mapOverlays.add(itemizedOverlay);
		latitude = "";
		longitude = "";
		Bundle extras = getIntent().getExtras();
		Log.e("extras", extras.size() + "");
		restaurant_id = extras.getString("loca_key");
		restaurant_name = extras.getString("loca_name");
		Log.e("loca_key", restaurant_id);
		System.out.println("rest name = " + restaurant_name);
		not_found = this.getResources().getString(R.string.address_not_found);
		if (restaurant_name.length() > 0) {
			String[] txt = restaurant_name.split(" ");
			area = txt[0];
			for (int i = 1; i < txt.length; i++)
				area = area + "+" + txt[i];
		}
		System.out.println(area);
		new Mapview().execute();

	}// end of onCreate

	/***
	 * This class extends AsyncTask to be able to display w spinning loader till
	 * the location data is fetched from the server & the map starts loading
	 * 
	 * @author dinahelal
	 * 
	 */
	class Mapview extends AsyncTask<Void, Void, String> {

		private ProgressDialog pdia;

		/***
		 * Called when executing the class Mapview, it starts the spinning
		 * loader
		 * 
		 */
		@Override
		protected void onPreExecute() {
			Log.e("preexecute", "in preexecute");

			pdia = ProgressDialog.show(MapViewActivity.this, "",
					"Loading.....", true);
		}// end of onPreExecute

		/***
		 * Called when the executing the class is cancelled
		 * 
		 */
		@Override
		public void onCancelled() {
			Log.e("cancelled", "in oncancelled");
			pdia.dismiss();
		}// end of onCancelled

		/***
		 * Called after the loader is dismissed
		 * 
		 */
		@Override
		protected void onPostExecute(String result) {
			Log.e("postexecute", "in post execute");
			pdia.dismiss();
		}// end of onPostExecute

		/***
		 * Called while the onPreExecute is running
		 * 
		 */
		@Override
		protected String doInBackground(Void... params) {
			Log.e("bgid", restaurant_id);
			googleMapsLocations(area);
			return "done";
		}// end of doInBackground
	}

	/***
	 * Creates buttons that will be displayed in the menu when this activity is
	 * created
	 * 
	 * @param menu
	 *            menu associated with this activity
	 * 
	 * @return return true when the menu buttons are created
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.address_menu, menu);
		return true;
	}// end of onCreateOptionsMenu

	/***
	 * Handles selecting an item from the menu
	 * 
	 * @param item
	 *            selected menu item
	 * 
	 * @return returns true after doing the action associated with selecting the
	 *         item
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle item selection
		if (item.getItemId() == R.id.add_address_menuItem) {
			Intent intent = new Intent(MapViewActivity.this, RestaurantMap.class);
			intent.putExtra("rest_name", restaurant_name);
			intent.putExtra("rest_id", restaurant_id);
			startActivity(intent);
		}
		return super.onOptionsItemSelected(item);
	}

	/***
	 * Searches for the area location in google maps & displays it on the map,
	 * if the area is not found, it looks for locations of the restaurant in the
	 * db & displays it if found
	 * 
	 * @param area
	 *            location that is initially sent to the search engine to look
	 *            for
	 * 
	 */
	public void googleMapsLocations(String area) {
		loca_retrived = true;
		System.out.println("get google location" + area);
		query = getJSONObject("https://maps.googleapis.com/maps/api/place/search/json?location=30.044244,31.237135&radius=50000&name="
				+ area
				+ "&sensor=false&key=AIzaSyD0Xk46UiDmamo3TOkcB3iMdXZnZXPHvTs");

		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				try {
					if (query != null) {
						double lat = 0;
						double lng = 0;

						results = new JSONArray();
						JSONObject jsonLocation;
						MapController mc = mapView.getController();
						results = query.getJSONArray("results");
						System.out.println("results = " + results.length());
						for (int i = 0; i < results.length(); i++) {
							jsonLocation = results.getJSONObject(i)
									.getJSONObject("geometry")
									.getJSONObject("location");
							lat = Double.parseDouble(jsonLocation
									.getString("lat"));
							lng = Double.parseDouble(jsonLocation
									.getString("lng"));
							p = new GeoPoint((int) (lat * 1E6),
									(int) (lng * 1E6));

							OverlayItem overlayitem = new OverlayItem(p, "", "");
							itemizedOverlay.addOverlay(overlayitem);
							
						}
						mc.animateTo(p);
						mc.setZoom(10);
						
						in = null;
						loca_retrived = false;
						mapOverlays.add(itemizedOverlay);
					}
				} catch (Exception e) {
					Log.e("jsonArray", e.getMessage(), e);
				}
			}
		});
		getDishLocationsDB(restaurant_id);
		
	}

	/***
	 * Called when the application is resumed after being paused due to
	 * interruption by call or force quit
	 * 
	 */
	@Override
	protected void onResume() {
		if (loca_retrived)
			googleMapsLocations(area);
		super.onResume();
	}

	/***
	 * Retrieves restaurant locations (latitude & longitude) from the database &
	 * saves them in latitude & longitude strings
	 * 
	 * @param id
	 *            Restaurant id where the dish is located
	 */
	public void getDishLocationsDB(String id) {
		Log.e("getloc", "in get dish locations");
		try {
			DefaultHttpClient CLIENT = new DefaultHttpClient();
			List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
			nameValuePairs.add(new BasicNameValuePair("id", id));
			URI url = URIUtils.createURI("http", Main.SERVER, -1, PATH1,
					URLEncodedUtils.format(nameValuePairs, "UTF-8"), null);
			HttpGet httpget = new HttpGet(url);
			HttpResponse resp = CLIENT.execute(httpget);
			StatusLine statusLine = resp.getStatusLine();
			int statusCode = statusLine.getStatusCode();
			Log.e("statuscode", statusCode + "");

			final StringBuilder respStr = new StringBuilder();
			HttpEntity entity = resp.getEntity();
			InputStream content = entity.getContent();
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					content));
			String line;
			while ((line = reader.readLine()) != null) {
				respStr.append(line);
			}
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					try {
						// read returned json objects
						System.out.println("respStr = "+respStr);
						JSONArray jsonArray = new JSONArray(respStr.toString());
						for (int i = 0; i < ((JSONArray) jsonArray.get(0))
								.length(); i++) {
							JSONObject jsonObject = ((JSONArray) jsonArray
									.get(0)).getJSONObject(i);
							JSONArray j_coords = jsonObject
									.getJSONArray("latitude");

							for (int j = 0; j < j_coords.length(); j++)
								latitude += j_coords.getString(j) + "#";
						}
						for (int i = 0; i < ((JSONArray) jsonArray.get(1))
								.length(); i++) {
							JSONObject jsonObject = ((JSONArray) jsonArray
									.get(1)).getJSONObject(i);
							JSONArray j_coords = jsonObject
									.getJSONArray("longitude");

							for (int j = 0; j < j_coords.length(); j++)
								longitude += j_coords.getString(j) + "#";
						}
						System.out.println("latitude =" +latitude);
						System.out.println("longitude =" +longitude);
						
						MapController mc = mapView.getController();
						System.out.println("latt = "+latitude);
						System.out.println("lon = "+longitude);
						if(!latitude.equals("") && !longitude.equals(""))
						{
						String[] latt = latitude.split("#");
						String[] lon = longitude.split("#");
						if (latt.length == 0)
							Toast.makeText(getBaseContext(),
									not_found,
									Toast.LENGTH_LONG).show();
						System.out.println("latt.length = "+latt.length);
						System.out.println("lon.length = "+lon.length);
						for (int i = 0; i < latt.length; i++) {
							System.out.println("latt[i] = "+latt[i]);
							System.out.println("lon[i] = "+lon[i]);
							p = new GeoPoint((int) (Double.parseDouble(latt[i]) * 1E6), (int) ((Double.parseDouble(lon[i])) * 1E6));
							OverlayItem overlayitem = new OverlayItem(p, "", "");
							itemizedOverlay.addOverlay(overlayitem);
						}
						mc.animateTo(p);
						mapOverlays.add(itemizedOverlay);
						mc.setZoom(10);
						}
						
						
					} catch (Exception e) {
						runOnUiThread(new Runnable() {
							@Override
							public void run() {
						
							}
						});
					}
				}
			});
		} catch (Exception e) {
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
			
				}
			});
		}

	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	/***
	 * Establishes a connection & sends a post request to get locations of a certain
	 * place from google places api
	 * 
	 * @param Url
	 * 			url sent to get addresses from google maps
	 * @return
	 * 			return response in the form of json object
	 */
	public static JSONObject getJSONObject(String Url) {
		System.out.println("URL = "+Url);
		String res = null;
		JSONObject producedObject = null;
		initURL(Url);
		connect();
		try {
			res = convertStreamToString(in);
			System.out.print("PRINTING RES");
			System.out.print(res);
			producedObject = new JSONObject(res);
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return producedObject;
	}

	/***
	 * 
	 * @param url
	 * 			url used to get addresses from google places api
	 */
	private static void initURL(String url) {
		try {
			myURL = new URL(url);
		} catch (MalformedURLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}

	/***
	 * Opens a connection & sends the request to get the locations
	 * from google api
	 * 
	 */
	private static void connect() {
		try {
			int retry = 0;
			while (retry < 3 && in == null) {
				uc = myURL.openConnection();
				uc.setReadTimeout(10000);
				uc.setConnectTimeout(10000);
				in = uc.getInputStream();
				System.out.println(in.toString());
				retry++;
			}
			System.out.println("out of connect");
		} catch (IOException e) {
			System.out.println("IO EXCEPTION connect");
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * To convert the InputStream to String we use the BufferedReader.readLine()
	 * method. We iterate until the BufferedReader return null which means
	 * there's no more data to read. Each line will appended to a StringBuilder
	 * and returned as String.
	 * 
	 * @param is
	 *            Inputstream
	 */
	private static String convertStreamToString(InputStream is) {
		System.out.println("in convert stream " + is);
		if (is != null) {
			StringBuilder sb = new StringBuilder();
			String line;
			try {
				BufferedReader reader = new BufferedReader(
						new InputStreamReader(is, "ISO_8859_1"), 16192);
				while ((line = reader.readLine()) != null) {
					sb.append(line).append("\n");
				}
			} catch (IOException e) {
				System.out.println("IO EXCEPTION");
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				try {
					is.close();
				} catch (IOException e) {
					System.out.println("IO EXCEPTION2");
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			System.out.println("out of convert stream " + in);
			return sb.toString();
		} else {
			return "";
		}
	}
}